package com.bj58.mis.apm.server.kylin.common;

import com.bj58.mis.apm.server.kylin.common.hllc.HLLCounter;
import com.bj58.mis.apm.server.kylin.common.util.SumHelper;
import com.bj58.mis.apm.server.kylin.model.CubeCuboid;
import com.bj58.mis.apm.server.kylin.model.CubeStatistic;
import com.bj58.mis.apm.server.kylin.model.Segment;
import com.google.common.collect.Maps;

import java.io.IOException;
import java.util.*;

public class CubeStatsReader {

    private Segment seg;
    private int samplingPercentage;
    private int mapperNumberOfFirstBuild;
    private double mapperOverlapRatioOfFirstBuild;
    private Map<Long, HLLCounter> cuboidRowEstimatesHLL;
    private long full_mark;
    private String full_mark_str;

    private Map<Long, Long> cuboidRows;

    public CubeStatsReader(String seqfile, Segment seg) throws IOException {
        int precision = 14;
        CubeStatsResult result = new CubeStatsResult(seqfile, precision);
        if(result != null) {
            this.seg = seg;
            this.samplingPercentage = result.getPercentage();
            this.mapperNumberOfFirstBuild = result.getMapperNumber();
            this.mapperOverlapRatioOfFirstBuild = result.getMapperOverlapRatio();
            this.cuboidRowEstimatesHLL = result.getCounterMap();
            this.full_mark = seg.getCube().getCubeDesc().getFull_mark();
            this.full_mark_str = (Long.toBinaryString(this.full_mark)).replaceAll("1","0");
        }
    }

    public CubeStatistic getCubeStatistic(){
        CubeStatistic cs = new CubeStatistic();
        cs.setCubeId(seg.getCube().getUuid());
        cs.setSegmentId(seg.getUuid());
        cs.setPercentage(this.samplingPercentage);
        cs.setMapperNumber(this.mapperNumberOfFirstBuild);
        cs.setMapperOverlapRatio(this.mapperOverlapRatioOfFirstBuild);
        cs.setCuboids(this.cuboidRows.size());
        cs.setEstimatedRows(SumHelper.sumLong(this.cuboidRows.values()));

        List<CubeCuboid> ids = new ArrayList<>();
        cs.setCuboidList(ids);
        for(Map.Entry<Long, Long> en : this.cuboidRows.entrySet()){
            CubeCuboid id = new CubeCuboid();
            id.setCuboid(en.getKey().intValue());
            id.setRowCount(en.getValue().intValue());
            id.setName(getName(id.getCuboid()));
            id.setCubeId(cs.getCubeId());
            id.setSegmentId(cs.getSegmentId());
            id.setPcuboid(this.seg.getCube().getCubeDesc().getCuboidScheduler().getChild2parent().get(id.getCuboid()));

            ids.add(id);
        }
        return cs;
    }

    private String getName(long id){
        String b = full_mark_str + Long.toBinaryString(id);
        b = b.substring(b.length() - this.full_mark_str.length());
        return b;
    }

    public CubeStatsReader build(){
        this.cuboidRows = this.getCuboidRowEstimatesHLL();
        return this;
    }

    public Map<Long, Long> getCuboidRowEstimatesHLL() {
        return getCuboidRowCountMapFromSampling(this.cuboidRowEstimatesHLL, this.samplingPercentage);
    }

    public static Map<Long, Long> getCuboidRowCountMapFromSampling(Map<Long, HLLCounter> hllcMap, int samplingPercentage) {
        Map<Long, Long> cuboidRowCountMap = Maps.newHashMap();
        Iterator it = hllcMap.entrySet().iterator();

        while(it.hasNext()) {
            Map.Entry<Long, HLLCounter> entry = (Map.Entry)it.next();
            cuboidRowCountMap.put(entry.getKey(), ((HLLCounter)entry.getValue()).getCountEstimate());
        }

        return cuboidRowCountMap;
    }

    public static void main(String[] args) throws Exception {
        String seqfile = "file:///D:\\temp\\da1196f1-dca7-4304-bd8c-f5ac15785172.seq";
        new CubeStatsReader(seqfile,null);
    }


}
